
#include "unzip.h"
#include "zip.h"
#include "ZipUtil.h"
#include "log.h"
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <cstring>
#include <sys/stat.h>



extern "C"
{
	#include "md5.h"
}
#define BUFFER_SIZE 1024

typedef struct 
{
    unzFile unzfile;
    unz_global_info glbInfo;
}Image_Ctl_t;


int ZipUtil::unZipFile(const std::string& filePath, const std::string &savePath){
    int i;
    int result=0;
    int ret;
    Image_Ctl_t imageCtl;
    unz_file_info secInfo;
    char secName[40] = {0}, fileName[40]={0};
    FILE *pFp=NULL;
    char fileList[512]={0};
    char *pBuf = NULL;
    int readLen;
    int sectorSize = 128*1024;
    char setenvCmd[256]={0};

    memset(&imageCtl, 0, sizeof(imageCtl));

    imageCtl.unzfile = unzOpen(filePath.c_str());
    if(imageCtl.unzfile == NULL)
    {
        LOG_PrintError("unzOpen %s failed!\n", filePath.c_str());
        return -1;
    }

    pBuf = (char *)malloc(sectorSize);
    if (!pBuf)
    {
        LOG_PrintError("malloc failed!\n");
        result = -1;
        goto close_file;
    }

    ret = unzGetGlobalInfo(imageCtl.unzfile, &imageCtl.glbInfo);
    if(ret != UNZ_OK)
    {
        LOG_PrintError("unzGetGlobalInfo failed!\n");
        result = -1;
        goto close_file;
    }

    result = unzGoToFirstFile(imageCtl.unzfile);
    if(result != UNZ_OK)
    {
        LOG_PrintError("unzGoToFirstFile failed!\n");
        result = -1;
        goto close_file;
    }

	std::string path =  savePath + "/%s";
    for(i=0; i<(int)imageCtl.glbInfo.number_entry; i++)
    {
        ret = unzGetCurrentFileInfo(imageCtl.unzfile,
                                    &secInfo,
                                    secName,
                                    sizeof(secName),
                                    NULL,
                                    0,
                                    NULL,
                                    0);
        if(ret != UNZ_OK)
        {
            LOG_PrintError("unzGetCurrentFileInfo failed!\n");
            return -1;
        }
#if 0
        if (strstr(secName, ".jpg") == NULL)
        {
            unzGoToNextFile(imageCtl.unzfile);
            continue;
        }
#endif

        LOG_PrintInfoRaw("Image Name: %s\n", secName);

        result = unzOpenCurrentFile(imageCtl.unzfile);
        if(result != UNZ_OK)
        {
            LOG_PrintError("unzOpenCurrentFile failed!\n");
            ret = -1;
            goto close_file;
        }

        
		LOG_PrintInfo("path:%s\n", path.c_str());
        sprintf(fileName, path.c_str(), secName);

        if (strlen(fileList))
        {
            strcat(fileList, ",");
        }
        strcat(fileList, secName);

        pFp = fopen(fileName, "w+");
        if (!pFp)
        {
            LOG_PrintError("open %s failed!\n", fileName);
            unzCloseCurrentFile(imageCtl.unzfile);
            ret = -1;
            goto close_file;
        }

        while (1)
        {
            readLen = unzReadCurrentFile(imageCtl.unzfile,
                                         pBuf,
                                         sectorSize);
            if (readLen < 0)
            {
                LOG_PrintError("unzReadCurrentFile failed!\n");
                unzCloseCurrentFile(imageCtl.unzfile);
                ret = -1;
                goto close_file;
            }
            else if (readLen == 0)
            {
                fclose(pFp);
                unzCloseCurrentFile(imageCtl.unzfile);
                break;
            }
            else
            {
                fwrite(pBuf, readLen, 1, pFp);
                fflush(pFp);
            }
        }

        unzGoToNextFile(imageCtl.unzfile);
    }
    
    close_file:
    unzClose(imageCtl.unzfile);

    if (pBuf)
    {
        free(pBuf);
    }

    return 0;
}




bool ZipUtil::compressFile(const std::set<std::string> &zipFiles, const std::string& zipFilePath) {
    // 检查压缩文件是否存在，如果不存在则创建一个新的文件并设置权限为777
    int zipFileDescriptor = open(zipFilePath.c_str(), O_WRONLY | O_CREAT, 0777);
    if (zipFileDescriptor < 0) {
        LOG_PrintError("Error creating %s\n", zipFilePath.c_str());
        return false;
    }
    close(zipFileDescriptor);  // 关闭文件描述符

    // 打开要写入的压缩文件
    zipFile zf = zipOpen(zipFilePath.c_str(), APPEND_STATUS_CREATE);
    if (zf == NULL) {
        LOG_PrintError("Error creating %s\n", zipFilePath.c_str());
        return false;
    }

    

    std::string fileName;
    size_t file_size;
    FILE *file;
    for(std::string zipFile :zipFiles){
        // 打开要添加到压缩文件中的文件
        file = fopen(zipFile.c_str(), "rb");
        if (file == NULL) {
            LOG_PrintError("Error opening %s\n", zipFile);
            zipClose(zf, NULL);
            return false;
        }

        // 获取文件大小
        struct stat file_stat;
        if (stat(zipFile.c_str(), &file_stat) != 0) {
            LOG_PrintError("Error getting file size of %s\n", zipFile);
            fclose(file);
            zipClose(zf, NULL);
            return false;
        }
        file_size = file_stat.st_size;
        // 获取不包含路径的文件名
        fileName =  basename(strdup(zipFile.c_str()));
        if(fileName.find("describe") != std::string::npos){
            fileName = "describe";
        }
        // 一次性写入整个文件
        if (zipOpenNewFileInZip(zf, fileName.c_str(), NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION) != ZIP_OK) {
            LOG_PrintError("Error opening file in zip\n");
            fclose(file);
            zipClose(zf, NULL);
            return false;
        }
        char *buffer = new char[file_size];
        if (fread(buffer, 1, file_size, file) != file_size) {
            LOG_PrintError("Error reading file %s\n", zipFile);
            delete[] buffer;
            fclose(file);
            zipClose(zf, NULL);
            return false;
        }

        if (zipWriteInFileInZip(zf, buffer, file_size) < 0) {
            LOG_PrintError("Error writing file data to %s\n", zipFile);
            delete[] buffer;
            fclose(file);
            zipClose(zf, NULL);
            return false;
        }

        delete[] buffer;
        fclose(file);
    }

    if (zipClose(zf, NULL) != ZIP_OK) {
        LOG_PrintError("Error closing zip files\n");
        return false;
    }

    return true;
}



bool ZipUtil::getMd5(string filePath , unsigned int &size, string &md5){
	unsigned char *pData;
	unsigned char outputTemp[16] = {0};
	char md[32] = {0};

	//新的方式打开，否则会出现段错误
	int fd = open(filePath.c_str(),O_RDWR);
	if (fd < 0)
	{
		LOG_PrintError("open %d failed!\n", fd);
		return false;
	}
	size = lseek(fd, 0, SEEK_END);

	pData = (unsigned char *)mmap(NULL,
								  size,
								  PROT_READ,
								  MAP_PRIVATE,
								  fd,
								  0);
	md5_calc(outputTemp, pData, size);	

	
	sprintf(md, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", outputTemp[0],outputTemp[1], outputTemp[2], outputTemp[3], outputTemp[4],
					outputTemp[5], outputTemp[6], outputTemp[7], outputTemp[8], outputTemp[9], outputTemp[10], outputTemp[11], outputTemp[12], outputTemp[13], outputTemp[14], outputTemp[15]);
	printf("md:%s\n", md);
					
	md5 = md;
    munmap((void *)pData, size);
	close(fd);
	return true;
}